package com.sise.cn.dao.base;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.sise.cn.dao.annotation.IgnoreField;
import com.sise.cn.dao.annotation.PrimaryId;
import com.sise.cn.dao.annotation.UniqueIndex;
import com.sise.cn.utils.Maps;
import com.sise.cn.utils.Pair;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName TableSpace
 * @Description 默认查询倒序
 * @Author CCJ
 * @Date 2020/6/2 22:42
 **/
@Data
@Slf4j
public abstract class TableSpace {

    /**
     * 主键
     */
    @PrimaryId
    private Long id;

    /**
     * 软删除标识
     */
    private Integer deleted;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;

    @IgnoreField
    @JSONField(serialize = false, deserialize = false)
    private List<Map<String, Boolean>> __orderBy__ = new ArrayList<>();

    @IgnoreField
    @JSONField(serialize = false, deserialize = false)
    private List<String> __groupBy__ = new ArrayList<>();

    @IgnoreField
    @JSONField(serialize = false, deserialize = false)
    private static final Pattern HUMP_PATTERN = Pattern.compile("[A-Z]");

    /**
     * 以下是查询条件
     */
    @IgnoreField
    @JSONField(serialize = false, name = "startTime")
    private String __startTime__;

    @IgnoreField
    @JSONField(serialize = false, name = "page")
    private Integer __page__;

    @IgnoreField
    @JSONField(serialize = false, name = "limit")
    private Integer __limit__;

    @IgnoreField
    @JSONField(serialize = false, name = "endTime")
    private String __endTime__;

    @IgnoreField
    @JSONField(serialize = false, name = "time")
    private Date __time__;

    protected List<Map<String, Object>> invokeParams() {
        List<Field> fields = getFields();
        List<Map<String, Object>> list = new ArrayList<>();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                Object o = field.get(this);
                //属性值为空的参数不加入参数列表
                if (o == null) {
                    continue;
                }
                String key = humpToLine(field.getName());
                if (field.getAnnotation(IgnoreField.class) != null) {
                    continue;
                }
                defaultSort(field, key);
                Map<String, Object> param = Maps.ofMap("key", key, "value", o);
                list.add(param);
            }
        } catch (IllegalAccessException e) {
            log.error("", e);
        }
        return list;
    }

    private void defaultSort(Field field, String key) {
        if (field.getAnnotation(PrimaryId.class) != null) {
            if (defaultPrimaryKeSort()) {
                addOrderByDesc(key);
            } else {
                addOrderByAsc(key);
            }
        }
    }

    /**
     * 获取POJO对象的属性列表
     * 会包含父类的字段
     *
     * @return 属性列表
     */
    private List<Field> getFields() {
        Class clazz = this.getClass();
        List<Field> fields = new ArrayList<>();
        //递归的获取父类的属性
        while (clazz != null) {
            Field[] fieldList = clazz.getDeclaredFields();
            for (Field field : fieldList) {
                //排除log属性字段
                if (field.getType() != org.slf4j.Logger.class) {
                    fields.add(field);
                }
            }
            clazz = clazz.getSuperclass();
        }
        return fields;
    }

    /**
     * 初始化更新所需参数
     * @param whereMap where条件列表
     * @return 更新的字段列表与值列表
     */
    protected Pair<Object, Object> initUpdate(Map<String, Object> whereMap) {
        ArrayList<LinkedHashMap<String, Object>> updateList = new ArrayList<>();
        for (Field field : getFields()) {
            LinkedHashMap<String, Object> valueMap = new LinkedHashMap<>();
            String key = humpToLine(field.getName());
            field.setAccessible(true);
            Object value = null;
            try {
                value = field.get(this);
            } catch (IllegalAccessException e) {
                log.error("获取字段属性值失败，原因是:{}",e.getMessage());
            }
            if (field.getAnnotation(IgnoreField.class) != null) {
                continue;
            }
            valueMap.put(key, value);
            updateList.add(valueMap);
        }
        ArrayList<Map<String, Object>> params = new ArrayList<>();
        for (Map.Entry<String, Object> entry : whereMap.entrySet()) {
            if(entry.getKey() != null && entry.getValue() != null && !"".equals(entry.getKey()) && !"".equals(entry.getValue())){
                params.add(Maps.ofMap("key", entry.getKey(), "value", entry.getValue()));
            }
        }
        return new Pair<>(params, updateList);
    }

    protected Pair<Object, Object> invokeUpdate() {
        Class clazz = this.getClass();
        Field[] fields = clazz.getDeclaredFields();
        Map<String, List<Map<String, Object>>> listMap = new HashMap<>();
        List<Map<String, Object>> params = new ArrayList<>();
        List<Map<String, Object>> updateList = new ArrayList<>();
        try {
            for (Field field : fields) {
                String key = humpToLine(field.getName());
                field.setAccessible(true);
                Object value = field.get(this);
                if (field.getAnnotation(IgnoreField.class) != null) {
                    continue;
                }
                Map<String, Object> map = Maps.ofMap("key", key, "value", value);
                if (field.getAnnotation(PrimaryId.class) != null) {
                    params.add(map);
                } else if (field.getAnnotation(UniqueIndex.class) != null) {
                    UniqueIndex unique = field.getAnnotation(UniqueIndex.class);
                    String name = unique.name();
                    if (!listMap.containsKey(name)) {
                        if (StringUtils.isEmpty(name)) {
                            name = UUID.randomUUID().toString();
                        }
                        listMap.put(name, new ArrayList<>());
                    }
                    //修复空指针
                    listMap.get(name).add(map);
                } else {
                    updateList.add(map);
                }
            }
        } catch (Exception e) {
            log.error("", e);
        }
        for (Map.Entry<String, List<Map<String, Object>>> entry : listMap.entrySet()) {
            List<Map<String, Object>> list = entry.getValue();
            for (Map<String, Object> item : list) {
                if (item.get("value") == null) {
                    updateList.addAll(list);
                    break;
                }
            }
            params.addAll(list);
        }
        return new Pair<>(params, updateList);
    }

    public void startPage(int page, int limit) {
        if (page == 0) {
            page = 1;
        }
        this.__page__ = (page - 1) * limit;
        this.__limit__ = limit;
    }

    public static String humpToLine(String str) {
        Matcher matcher = HUMP_PATTERN.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }


    public TableSpace addOrderByDesc(String field) {
        Map<String, Boolean> map = new HashMap<>();
        map.put(field, true);
        this.__orderBy__.add(map);
        return this;
    }

    public TableSpace addOrderByAsc(String field) {
        Map<String, Boolean> map = new HashMap<>();
        map.put(field, false);
        this.__orderBy__.add(map);
        return this;
    }

    public TableSpace addGroupBy(String field) {
        this.__groupBy__.add(field);
        return this;
    }

    protected boolean defaultPrimaryKeSort() {
        return true;
    }
}
